#include <sys_head.h>

void *Tcp_Server_func(void *arg);

// 定义一个全局变量的数组
typedef struct tpc_Sock_fds
{
    int Sock_fd;
    char name[128];
} tpc_Sock_fds;

#define MAX_LIST 20


// 全局变量存储用户顺序表
tpc_Sock_fds Sock_fds[MAX_LIST];

int arr_len = 0;

// 定义互斥锁
pthread_mutex_t lock;

int main(int argc, char const *argv[])
{
    // 判断命令行参数
    if (argc < 2)
    {
        printf("参数错误:%s ip port\n", argv[0]);
        return -1;
    }
    // 给定默认ip

    char ip_str[128];

    if (3 != argc)
    {

        strcpy(ip_str, "10.0.12.15");
    }
    else
    {

        strcpy(ip_str, argv[2]);
    }

    //  1、创建套接字
    int Sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == Sock_fd)
    {
        ERRLOG("socket erron");
        return -1;
    }

    //  2、填充服务器网络信息结构体
    struct sockaddr_in Sock_addr;
    Sock_addr.sin_family = AF_INET;                // 选择 IPV4
    Sock_addr.sin_port = htons(atoi(argv[1]));     // 给定端口 // atoi 将字符串 转换成数字
    Sock_addr.sin_addr.s_addr = inet_addr(ip_str); // IP地址

    socklen_t Sock_size = sizeof(Sock_addr);

    //  3、将套接字与服务器的网络信息结构体绑定
    if (-1 == bind(Sock_fd, (struct sockaddr *)&Sock_addr, Sock_size))
    {
        ERRLOG("bind err");
        return -1;
    }

    //  4、将套接字设置城 监听状态

    if (-1 == listen(Sock_fd, 20))
    {
        ERRLOG("Sock_fd err");
        return -1;
    }

    printf("有用户链接");

    pthread_t Tid;

    int index = 0;

    // 初始化锁
    pthread_mutex_init(&lock, NULL);

    while (1)
    {

        //  5、阻塞等待客户端连接 accept
        int acc_fd = accept(Sock_fd, NULL, NULL);
        if (-1 == acc_fd)
        {
            ERRLOG("accept err");
            return -1;
        }

        if (arr_len >= MAX_LIST)
        {
            printf("已经满了\n");
            send(acc_fd, "已经满了", strlen("已经满了"), 0);
            continue;
        }

        pthread_mutex_lock(&lock);

        // 更新顺序表
        Sock_fds[arr_len].Sock_fd = acc_fd;
        strcpy(Sock_fds[arr_len].name, "新用户2580");

        index = arr_len;
        pthread_mutex_unlock(&lock);

        // 创建线程 并传递 文件描述符给线程
        pthread_create(&Tid, NULL, Tcp_Server_func, (void *)&index);

        // 线程分离
        pthread_detach(Tid); // 不阻塞

        arr_len++;
    }

    //  7、关闭套接字  close
    close(Sock_fd);
    return 0;
}

void *Tcp_Server_func(void *arg)
{
    // 声明变量
    int index = *((int *)arg);
    char name[128];
    int Sock_fd;

    char buf[1024];
    char send_buf[2048];

    // 初始化数据
    Sock_fd = Sock_fds[index].Sock_fd;
    strcpy(name, Sock_fds[index].name);

    while (1)
    {
        memset(buf , 0 , sizeof(buf));

        recv(Sock_fd , buf , sizeof(buf) , 0);
        
        pthread_mutex_lock(&lock);

        // 修改名字
        if (NULL != strstr(buf , "set_name_"))
        {
            // 写入姓名
            strcpy( Sock_fds[index].name , buf + 9 );
            sprintf(buf , "修改名称成功:%s" , Sock_fds[index].name);
            send(Sock_fd , buf , strlen(buf) , 0);
        // 退出链接
        }
        else if (!strcmp(buf , "quit"))
        {
            // 组装
            sprintf(send_buf , "%s : %s" , Sock_fds[index].name ,"退出成功");
            send(Sock_fd , send_buf , strlen(send_buf) , 0);
            break;
        }
        
        // 转发 群发
        else
        {
            // 发送给其他成员
            for (size_t i = 0; i < MAX_LIST; i++)
            {
                // 组装字符串
                sprintf(send_buf , "%s : %s", Sock_fds[index].name , buf);

                if (Sock_fd != Sock_fds[i].Sock_fd)
                {
                    send(Sock_fds[i].Sock_fd , send_buf , strlen(send_buf) , 0);
                }
            }
        }
        pthread_mutex_unlock(&lock);
    }

    // 退出  关闭文件描述符   全局顺序表 就需要做删除  len --

    close(Sock_fd);

    // 从顺序表中删除
    pthread_mutex_lock(&lock);

    for (size_t i = index; i < MAX_LIST; i++)
    {
        Sock_fds[i] = Sock_fds[i + 1];
    }
    
    arr_len--;
    
    printf("链接已退出");

    pthread_mutex_unlock(&lock);

    return NULL;

}
